package com.link.play.fit.ai.ui.scanFood

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.ColorSpace
import android.graphics.ImageFormat
import android.graphics.Matrix
import android.graphics.Rect
import android.graphics.YuvImage
import android.media.Image
import android.os.Build
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicYuvToRGB
import android.renderscript.Type
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import com.link.play.fit.ai.MyApp
import com.link.play.fit.ai.utils.AppX
import java.io.ByteArrayOutputStream


//图形分析器
class QRImageAnalyzer() : ImageAnalysis.Analyzer {

    private val TAG = "QRImageAnalyzer"

    var parseAction: ((qrCodeValue: String, valueType: Int) -> Unit)? = null
    var imageAction: ((bitmap: Bitmap?) -> Unit)? = null

    //如需仅检测 Aztec 码和 QR 码
    private val options = BarcodeScannerOptions.Builder().setBarcodeFormats(
//        Barcode.FORMAT_QR_CODE, Barcode.FORMAT_AZTEC, Barcode.TYPE_URL, Barcode.TYPE_PRODUCT,
        Barcode.FORMAT_ALL_FORMATS
    ).build()

    //获取解析器
    private val detector = BarcodeScanning.getClient(options)

    @SuppressLint("UnsafeOptInUsageError")
    override fun analyze(imageProxy: ImageProxy) {
        val mediaImage = imageProxy.image
        if (mediaImage != null) {
//            Log.e(TAG, "mediaImage=$mediaImage")
            if (imageAction != null) {
                Log.e(TAG, "imageAction")
                val bitmap = if (mediaImage.getUPixelStride() == 1 && mediaImage.getVPixelStride() == 1) {
                    mediaImage.toBitmap(imageProxy.imageInfo.rotationDegrees)
                } else {
                    mediaImage.toBitmap3(imageProxy.imageInfo.rotationDegrees)
                }
                Log.e(TAG, "bitmap=$bitmap")
                imageAction?.invoke(bitmap)
                imageAction = null
            }
            val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
            detector.process(image).addOnSuccessListener { barcodeList ->

//                    barcodeList.forEach {
//                        LogEx.logDebug(TAG, "rawValue=${it.rawValue}")
//                    }
                handleBarcodeList(barcodeList)

            }.addOnFailureListener {
//                Log.e(TAG, "OnFailure")
            }.addOnCompleteListener {
//                Log.e(TAG, "OnComplete")
                imageProxy.close()
            }
        } else {
            imageProxy.close()
        }
    }

    private fun handleBarcodeList(
        barcodeList: List<Barcode>,
    ) {

        if (barcodeList.size == 1) {
            val barcode = barcodeList[0]
            val valueType = barcode.valueType
            val qrCodeValue = barcode.rawValue ?: ""
//            Barcode.FORMAT_QR_CODE, FORMAT_CODABAR, FORMAT_AZTEC, TYPE_TEXT
//            Log.e(TAG, "valueType=$valueType qrCodeValue=$qrCodeValue")
            parseAction?.invoke(qrCodeValue, valueType)
        }
    }

    fun processImage(context: Context, bitmap: Bitmap) {
        val image = InputImage.fromBitmap(bitmap, 0)
        val barcodeScanner = BarcodeScanning.getClient(options)

        barcodeScanner.process(image)
            .addOnSuccessListener { barcodes ->
                handleBarcodeList(barcodes)
            }
            .addOnFailureListener { exception ->
                // 处理失败情况
//                LogEx.logDebug(TAG,"$exception")
                Toast.makeText(context, "Unable to parse QR code", Toast.LENGTH_SHORT).show()
            }
    }

    fun Image.LogInfo() {
        val yPixelStride = planes[0].pixelStride
        val yRowStride = planes[0].rowStride
        val uPixelStride = planes[1].pixelStride
        val uRowStride = planes[1].rowStride
        val vPixelStride = planes[2].pixelStride
        val vRowStride = planes[2].rowStride

        Log.d("ImageToBitmap", "Y plane: pixelStride=$yPixelStride, rowStride=$yRowStride")
        Log.d("ImageToBitmap", "U plane: pixelStride=$uPixelStride, rowStride=$uRowStride")
        Log.d("ImageToBitmap", "V plane: pixelStride=$vPixelStride, rowStride=$vRowStride")
    }

    fun Image.getUPixelStride(): Int {
        val uPixelStride = planes[1].pixelStride
        val uRowStride = planes[1].rowStride
        Log.d("ImageToBitmap", "U plane: pixelStride=$uPixelStride, rowStride=$uRowStride")
        return uPixelStride
    }

    fun Image.getVPixelStride(): Int {
        val vPixelStride = planes[2].pixelStride
        val vRowStride = planes[2].rowStride
        Log.d("ImageToBitmap", "V plane: pixelStride=$vPixelStride, rowStride=$vRowStride")
        return vPixelStride
    }

    fun Image.toBitmap3(rotationDegrees: Int): Bitmap? {
        if (format != ImageFormat.YUV_420_888) {
            Log.e("ImageToBitmap", "Unsupported image format: ${format}")
            return null
        }

        val yBuffer = planes[0].buffer
        val uBuffer = planes[1].buffer
        val vBuffer = planes[2].buffer

        val yPixelStride = planes[0].pixelStride
        val yRowStride = planes[0].rowStride
        val uPixelStride = planes[1].pixelStride
        val uRowStride = planes[1].rowStride
        val vPixelStride = planes[2].pixelStride
        val vRowStride = planes[2].rowStride


        val ySize = width * height
        val uvSize = width * height / 4
        val nv21 = ByteArray(ySize + uvSize * 2)

        // Copy Y plane
        yBuffer.position(0)
        for (row in 0 until height) {
            val yStart = row * width
            val bufferPos = row * yRowStride
            yBuffer.position(bufferPos)
            yBuffer.get(nv21, yStart, width)
        }

        // For NV21, we need to interleave V and U samples (V first, then U)
        val uvRowCount = height / 2
        val uvWidth = width / 2
        val uvRowStride = uRowStride

        // Position in the NV21 array where the VU data starts
        var uvOffset = ySize

        for (row in 0 until uvRowCount) {
            val uRowStart = row * uRowStride
            val vRowStart = row * vRowStride

            for (col in 0 until uvWidth) {
                // Get V value
                val vPos = vRowStart + col * vPixelStride
                nv21[uvOffset++] = vBuffer.get(vPos)

                // Get U value
                val uPos = uRowStart + col * uPixelStride
                nv21[uvOffset++] = uBuffer.get(uPos)
            }
        }

        val yuvImage = YuvImage(
            nv21,
            ImageFormat.NV21,
            width,
            height,
            null
        )

        val out = ByteArrayOutputStream().apply {
            yuvImage.compressToJpeg(Rect(0, 0, width, height), 100, this)
        }
        val imageBytes = out.toByteArray()

        val options = BitmapFactory.Options().apply {
            inPreferredConfig = Bitmap.Config.ARGB_8888
            inPremultiplied = false
        }

        val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size, options)
            ?: return null

        return rotateBitmap(bitmap, rotationDegrees)
    }

    fun Image.toBitmap(rotationDegrees: Int): Bitmap? {
        if (format != ImageFormat.YUV_420_888) {
            Log.e("ImageToBitmap", "Unsupported image format: ${format}")
            return null
        }

        val yBuffer = planes[0].buffer
        val uBuffer = planes[1].buffer
        val vBuffer = planes[2].buffer

        val yPixelStride = planes[0].pixelStride
        val yRowStride = planes[0].rowStride
        val uPixelStride = planes[1].pixelStride
        val uRowStride = planes[1].rowStride
        val vPixelStride = planes[2].pixelStride
        val vRowStride = planes[2].rowStride
        //U/V平面pixelStride=2（正常应为1）：
        //这表示小米设备对UV数据使用了2字节的像素步长（隔行采样），而标准NV21格式要求UV数据必须是紧密排列（pixelStride=1）
        Log.d("ImageToBitmap", "Y plane: pixelStride=$yPixelStride, rowStride=$yRowStride")
        Log.d("ImageToBitmap", "U plane: pixelStride=$uPixelStride, rowStride=$uRowStride")
        Log.d("ImageToBitmap", "V plane: pixelStride=$vPixelStride, rowStride=$vRowStride")


        val ySize = yBuffer.remaining()
        val uSize = uBuffer.remaining()
        val vSize = vBuffer.remaining()

        val nv21 = ByteArray(ySize + uSize + vSize)

        // Copy Y data
        yBuffer.get(nv21, 0, ySize)

        // Interleave U and V data (NV21 format requires VU order)
        val uvBuffer = ByteArray(uSize + vSize)
        vBuffer.get(uvBuffer, 0, vSize)  // V first
        uBuffer.get(uvBuffer, vSize, uSize)  // U second

        // Copy UV data to the end of NV21 array
        System.arraycopy(uvBuffer, 0, nv21, ySize, uvBuffer.size)

        val yuvImage = YuvImage(
            nv21,
            ImageFormat.NV21,
            width,
            height,
            null
        )

        val out = ByteArrayOutputStream().apply {
            yuvImage.compressToJpeg(Rect(0, 0, width, height), 100, this)
        }
        val imageBytes = out.toByteArray()

        val options = BitmapFactory.Options().apply {
            inPreferredConfig = Bitmap.Config.ARGB_8888
            // Ensure proper color space handling
            inPremultiplied = false
        }

        val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size, options)
            ?: return null


        return rotateBitmap(bitmap, rotationDegrees)
    }

    private fun rotateBitmap(bitmap: Bitmap, degrees: Int): Bitmap {
        if (degrees == 0) return bitmap

        val matrix = Matrix().apply {
            postRotate(degrees.toFloat())
        }

        return Bitmap.createBitmap(
            bitmap,
            0,
            0,
            bitmap.width,
            bitmap.height,
            matrix,
            true
        )
    }
}